package cc.rengu.igas.bomp.core.service.trans;

import cc.rengu.igas.bomp.common.constant.BompAppParamConstant;
import cc.rengu.igas.bomp.common.constant.BompTreeNodeConstant;
import cc.rengu.igas.bomp.common.constant.DubboMethodConstant;
import cc.rengu.igas.bomp.common.dao.MchntAcctInfoMapper;
import cc.rengu.igas.bomp.common.dao.MchntBaseInfoMapper;
import cc.rengu.igas.bomp.common.dao.MchntSignInfoMapper;
import cc.rengu.igas.bomp.common.dao.impl.MchntAcctInfoMapperImpl;
import cc.rengu.igas.bomp.common.dao.impl.MchntBaseInfoMapperImpl;
import cc.rengu.igas.bomp.common.dao.impl.MchntSignInfoMapperImpl;
import cc.rengu.igas.bomp.common.entity.MchntAcctInfo;
import cc.rengu.igas.bomp.common.entity.MchntBaseInfo;
import cc.rengu.igas.bomp.common.entity.MchntSignInfo;
import cc.rengu.igas.bomp.common.enums.FundTypeEnum;
import cc.rengu.igas.bomp.common.enums.RespCodeEnum;
import cc.rengu.igas.bomp.common.util.InitParamUtil;
import cc.rengu.igas.bomp.core.service.base.ManageService;
import cc.rengu.igas.bomp.facade.request.SettleAccountSignRequest;
import cc.rengu.igas.bomp.facade.response.SettleAccountSignResponse;
import cc.rengu.igas.share.common.util.GlobalEsbUtil;
import cc.rengu.igas.smps.facade.base.Header;
import cc.rengu.igas.smps.facade.request.BankAcctInfoQueryRequest;
import cc.rengu.igas.smps.facade.response.BankAcctInfoQueryResponse;
import cc.rengu.igas.smps.facade.result.Result;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.SysParamMapper;
import cc.rengu.oltp.service.common.dao.impl.SysParamMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.utility.util.*;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhangxuran
 * @version 1.0
 * @date 2020/4/20 21:20
 * @description 结算账户核心签约
 * <p>
 * 业务处理流程：
 * 1、根据判断该商户的是否为独立维护商户资料的商户，若不是独立维护，则拒绝交易，结束流程
 * 2、根据获取到商户的结算账户列表信息，筛选出账户为入参的信息，若列表不为空则继续执行，若为筛选为空则拒绝交易，结束流程
 * 3、调用ESB接口进行核心账户签约
 * 4、更新结算账户列表信息为已签约
 */
public class SettleAccountSignService extends ManageService {

    @Override
    protected Object bizBeforeCust() throws Exception {
        SettleAccountSignRequest settleAccountSignRequest = new SettleAccountSignRequest();
        ConvertUtil.convertOutput(settleAccountSignRequest);
        if (StringUtil.isEmptyOrNull(settleAccountSignRequest.getMchntNo())
                || StringUtil.isEmptyOrNull(settleAccountSignRequest.getAcctNo())) {
            rglog.error("结算账户核心签约失败，必填项参数为空！");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }

        return settleAccountSignRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        SettleAccountSignRequest settleAccountSignRequest = (SettleAccountSignRequest) request;
        SettleAccountSignResponse settleAccountSignResponse = new SettleAccountSignResponse();
        BizResponse<SettleAccountSignResponse> bizResponse = new BizResponse<>();
        String instId = settleAccountSignRequest.getHeader().getInstId();
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);

        //根据法人行判断是否需要进行签约
        SysParamMapper sysParamMapper = new SysParamMapperImpl();
        SysParam sysParam = sysParamMapper.selectSysParamByPrimaryKey(instId, BompAppParamConstant.MCHNT_PARAM_TYPE, BompAppParamConstant.CORE_ACCT_SIGN);
        if (sysParam == null) {
            rglog.error("根据<instId:{}>,<paramType:{}>,<paramKey:{}>,未查询到系统参数表", instId, BompAppParamConstant.MCHNT_PARAM_TYPE, BompAppParamConstant.CORE_ACCT_SIGN);
            throw new BizException(RespCodeEnum.NOT_NEED_CORE_ACCT_SIGN.getRespCode(), RespCodeEnum.NOT_NEED_CORE_ACCT_SIGN.getRespDesc());
        }

        MchntBaseInfo mchntBaseInfo = (MchntBaseInfo) xmlTreeUtil.getXmlTreeObjectValue(BompTreeNodeConstant.MCHNT_BASE_INFO, MchntBaseInfo.class);
        if (null == mchntBaseInfo) {
            MchntBaseInfoMapper mchntBaseInfoMapper = new MchntBaseInfoMapperImpl();
            mchntBaseInfo = mchntBaseInfoMapper.selectMchntBaseInfoByPrimaryKey(instId, settleAccountSignRequest.getMchntNo());

            if (null == mchntBaseInfo) {
                rglog.error("结算账户核心签约处理失败，无商户信息,instId:{}, mchntNo:{}",
                        instId, settleAccountSignRequest.getMchntNo());
                throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
            }
        }

        //非独立维护商户资料
        if (BompAppParamConstant.FLAG_N.equals(mchntBaseInfo.getIndependentDataFlag())) {
            rglog.error("结算账户核心签约处理失败，该商户为非独立维护商户资料，不需要进行结算账户签约处理,instId:{}, mchntNo:{}",
                    instId, settleAccountSignRequest.getMchntNo());
            throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
        }

        MchntSignInfoMapper mchntSignInfoMapper = new MchntSignInfoMapperImpl();
        MchntSignInfo mchntSignInfo = mchntSignInfoMapper.selectMchntSignInfoByPrimaryKey(instId, mchntBaseInfo.getMchntNo());
        if (null == mchntSignInfo) {
            rglog.error("结算账户核心签约失败, 根据商户号查询商户签约信息为空，instId:{},mchntNo:{}", instId, settleAccountSignRequest.getMchntNo());
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }
        MchntAcctInfoMapper mchntAcctInfoMapper = new MchntAcctInfoMapperImpl();
        List<MchntAcctInfo> mchntAcctInfoList = mchntAcctInfoMapper.selectMchntAcctInfoByMchntNo(instId, settleAccountSignRequest.getMchntNo());
        if (CollectionUtils.isEmpty(mchntAcctInfoList)) {
            rglog.error("结算账户核心签约失败, 根据商户号查询商户结算账户信息为空，instId:{},mchntNo:{}", instId, settleAccountSignRequest.getMchntNo());
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }

        //过滤商户结算账户和传入参数的账户信息
        mchntAcctInfoList = mchntAcctInfoList.stream().filter(item -> BompAppParamConstant.FLAG_N.equals(item.getAcctSignFlag())
                && item.getSettleAcctNo().equals(settleAccountSignRequest.getAcctNo())
                && FundTypeEnum.SETTLE_TYPE.getFundCode().equals(item.getFundType())
                && InitParamUtil.isCoreBankType(item.getSettleAcctType())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(mchntAcctInfoList)) {
            rglog.error("结算账户核心签约处理结束，根据账户查询商户的结算账户表结算账户已签约!,instId:{}, sysSeqNum:{},mchnt:{}",
                    instId, sysSeqNum, settleAccountSignRequest.getMchntNo());
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            bizResponse.setResult(settleAccountSignResponse);
            return bizResponse;
        }

        if (CollectionUtils.isEmpty(txnInfo.getChannelCallCfgList())) {
            rglog.error("结算账户核心签约处理失败，txnInfo.getchannelCallCfgList 通道服务调用配置表无结算账户核心签约别配置数据!,instId:{}, sysSeqNum:{}",
                    instId, sysSeqNum);
            throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
        }

        ChannelCallCfg channelCallCfg = txnInfo.getChannelCallCfgList().stream().filter(item -> "00010000378901".equals(item.getCallChannelTxn())).collect(Collectors.toList()).get(0);

        //TODO 核心签约
        DubboService dubboService = new DubboServiceImpl();

        ChannelCallCfg coreAcctInfoQueryMap = txnInfo.getChannelCallCfgList().stream().filter(item -> "00010000200000".equals(item.getCallChannelTxn())).collect(Collectors.toList()).get(0);
        BankAcctInfoQueryRequest coreAcctInfoQueryRequest = new BankAcctInfoQueryRequest();
        Header headerQuery = new Header();
        BeanUtil.beanCopy(settleAccountSignRequest.getHeader(), headerQuery);
        headerQuery.setChanlId(ChannelEnum.BOMP.getChannelType());
        headerQuery.setSrcSysId(AppParamConstant.SYS_ID);
        headerQuery.setTxnNum(coreAcctInfoQueryMap.getCallChannelTxn());
        headerQuery.setTraceNo(GlobalEsbUtil.generateEsbSeqeuenceNumber(instId));
        coreAcctInfoQueryRequest.setHeader(headerQuery);
        coreAcctInfoQueryRequest.setAcctNo(settleAccountSignRequest.getAcctNo());
        coreAcctInfoQueryRequest.setCertType(mchntSignInfo.getArtifCertType());
        Result<BankAcctInfoQueryResponse> coreAcctInfoQueryResponse = (Result<BankAcctInfoQueryResponse>) dubboService.callDubboService(DubboMethodConstant.DUBBO_BANK_SUP_SERVICE, "bankAcctInfoQuery", coreAcctInfoQueryRequest);
        if (null == coreAcctInfoQueryResponse || null == coreAcctInfoQueryResponse.getResult()) {
            rglog.error("结算账户核心签约查询处理失败！调用ESB通道的核心账户签约查询coreAcctInfoQueryResponse返回失败!");
            throw new BizException(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
        } else if (!coreAcctInfoQueryResponse.isSuccess() || !DubboMethodConstant.DUBBO_SUCCESS.equals(coreAcctInfoQueryResponse.getResult().getRespCode())) {
            rglog.error("结算账户核心签约查询处理失败！调用ESB通道的核心账户签约查询coreAcctInfoQueryResponse返回失败,errorCode:{},errorMsg:{}",
                    coreAcctInfoQueryResponse.getResult().getRespCode(), coreAcctInfoQueryResponse.getResult().getRespDesc());
            throw new BizException(coreAcctInfoQueryResponse.getResult().getRespCode(), coreAcctInfoQueryResponse.getResult().getRespDesc());
        }

        updateAcctSignFlag(settleAccountSignRequest, sysSeqNum, mchntAcctInfoMapper, mchntAcctInfoList.get(0), coreAcctInfoQueryResponse.getResult());

        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setResult(settleAccountSignResponse);
        return bizResponse;
    }

    private void updateAcctSignFlag(SettleAccountSignRequest settleAccountSignRequest,
                                    String sysSeqNum,
                                    MchntAcctInfoMapper mchntAcctInfoMapper, MchntAcctInfo mchntAcctInfo,
                                    BankAcctInfoQueryResponse coreAcctInfoQueryResponse) throws Exception {

        //核心客户号
        mchntAcctInfo.setCoreCustomerId(coreAcctInfoQueryResponse.getCoreCustomerNo());
        mchntAcctInfo.setAcctSignFlag(BompAppParamConstant.FLAG_Y);
        mchntAcctInfo.setLastOprId(settleAccountSignRequest.getUserId());
        mchntAcctInfo.setLastUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        int dbResult = mchntAcctInfoMapper.updateAcctSignFlagById(mchntAcctInfo);
        if (dbResult != 0) {
            rglog.error("更新商户结算信息表核心账户签约标识失败,sysSeqNum:<{}>,iReturnCode:<{}>",
                    sysSeqNum, dbResult);
            throw new BizException(RespCodeEnum.DATABASE_OPR_ERROR.getRespCode(), RespCodeEnum.DATABASE_OPR_ERROR.getRespDesc());
        }
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        SettleAccountSignResponse settleAccountSignResponse = (SettleAccountSignResponse) bizResponse.getResult();
        ConvertUtil.convertInput(settleAccountSignResponse);
    }
}
